/*
 * EvolutiveCaseGenerator.cpp
 *
 *  Created on: 29/05/2011
 *      Author: godinho
 */

#include <evolutive/EvolutiveCaseGenerator.h>

#include <iostream>
#include <utils.h>

EvolutiveCaseGenerator::EvolutiveCaseGenerator() {
	mRecycler = CaseRecycler::getInstance();
	mParents = std::vector<Case*>();
	mChildren = std::vector<Case*>();
	mFitnessFunction = 0;
	mLifeSimulator = 0;
	mCaseSelector = 0;
	mOffspringGenerator = 0;
	mEndIterations = false;
}

EvolutiveCaseGenerator::~EvolutiveCaseGenerator() {
	delete mFitnessFunction;
	delete mLifeSimulator;
	delete mCaseSelector;
	delete mOffspringGenerator;
}

void EvolutiveCaseGenerator::setLocalview(localview::LocalView* lv) {
	mLocalview = lv;
}

void EvolutiveCaseGenerator::startEvolution(std::vector<Case*> cases) {
	mParents.clear();
	mChildren.clear();

	std::vector<Case*> aux;
	std::vector<Case*> sons;

	std::vector<Case*>::iterator casesIt;
	for(casesIt = cases.begin(); casesIt != cases.end(); casesIt++){
		mParents.push_back(*casesIt);
	}

	int id = 0;
	int generationNum = 0;

	Case* parent1;
	Case* parent2;

	while(!timedOut()) {
		id = 0;
		//TODO include log code
		//std::cout << "Generation " << generationNum << "\n";

		if(mListener != 0) {
			mListener->newGeneration(generationNum);
		}

		//Generate sons
		for(unsigned int i = 0; i < mParents.size()/2; i++) {

			//Select parents
			parent1 = mCaseSelector->select(mParents);
			parent2 = mCaseSelector->select(mParents);
			//std::cout << parent1->getId() << " " << parent2->getId();

			sons = mOffspringGenerator->generate(parent1, parent2, id);

			mChildren.push_back(sons[0]);
			mChildren.push_back(sons[1]);

			id+=2;
		}

		mLifeSimulator->simulate(mChildren, mLocalview, 60);

		for(casesIt = mChildren.begin(); casesIt != mChildren.end(); casesIt++) {
			float fitness = mFitnessFunction->fitness(*casesIt);
			(*casesIt)->setFitness(fitness);
		}

		mListener->generation(mChildren);

		//Recycle parents cases
		if(generationNum > 0) {
			killGeneration(mParents);
		}

		//Children become parents, and parents are cleared
		mParents = mChildren;
		mChildren.clear();

		generationNum++;
	}
}

std::vector<Case*> EvolutiveCaseGenerator::getCases() {
	return mParents;
}

void EvolutiveCaseGenerator::killGeneration(std::vector<Case*> cases) {
	std::vector<Case*>::iterator it;

	for(it = cases.begin(); it != cases.end(); it++) {
		mRecycler->die(*it);
	}
}

bool EvolutiveCaseGenerator::timedOut() {
	return mEndIterations;
}

void EvolutiveCaseGenerator::setEventListener(EventListener* listener) {
	mListener = listener;
}

void EvolutiveCaseGenerator::setFitnessFunction(FitnessFunction* fitnessFunction) {
	mFitnessFunction = fitnessFunction;
}

void EvolutiveCaseGenerator::setLifeSimulator(LifeSimulator* lifeSimulator) {
	mLifeSimulator = lifeSimulator;
}

void EvolutiveCaseGenerator::setCaseSelector(CaseSelector* selector) {
	mCaseSelector = selector;
}

void EvolutiveCaseGenerator::setOffspringGenerator(OffspringGenerator* offspringGenerator) {
	mOffspringGenerator = offspringGenerator;
}

FitnessFunction* EvolutiveCaseGenerator::getFitnessFunction() {
	return mFitnessFunction;
}

LifeSimulator* EvolutiveCaseGenerator::getLifeSimulator() {
	return mLifeSimulator;
}

CaseSelector* EvolutiveCaseGenerator::getCaseSelector() {
	return mCaseSelector;
}

OffspringGenerator* EvolutiveCaseGenerator::getOffspringGenerator() {
	return mOffspringGenerator;
}

void EvolutiveCaseGenerator::setTimedOut() {
	mEndIterations = true;
	mLifeSimulator->stopSimulation();
}
